/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.engine.core;

import io.iec.edp.caf.boot.context.CAFContext;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

public class BefEngineInfoCache {

//  private static Map<String, BefEngineInfo> maps = new HashMap<>(1000);
  //BEId和租户的映射关系 key为beId value为租户信息，较少
  private static ConcurrentHashMap<String, CopyOnWriteArrayList<BETenantInfo>> tenantBEMap = new ConcurrentHashMap<>();
  private static ConcurrentHashMap<Integer, ConcurrentHashMap<String, BefEngineInfo>> tenantMap = new ConcurrentHashMap<>();
  public static BefEngineInfo getBefEngineInfo(String beId) {
    int tenantId = CAFContext.current.getTenantId();
    if(tenantMap.containsKey(tenantId)){
      ConcurrentHashMap<String, BefEngineInfo> befEngineInfoMap = tenantMap.get(tenantId);
      if(befEngineInfoMap.containsKey(beId))
        return befEngineInfoMap.get(beId);
      synchronized (befEngineInfoMap) {
        if (befEngineInfoMap.containsKey(beId))
          return befEngineInfoMap.get(beId);
        BefEngineInfo info = new BefEngineInfo();
        befEngineInfoMap.put(beId, info);
        return info;
      }
    }
    //没有版本的，直接new就行
    ConcurrentHashMap<String, BefEngineInfo> befEngineInfoMap = new ConcurrentHashMap<>();
    BefEngineInfo info = new BefEngineInfo();
    befEngineInfoMap.put(beId, info);
    tenantMap.put(tenantId, befEngineInfoMap);
    return info;
  }

  public static BefEngineInfo getBefEngineInfo(String beId, String version) {
    int tenantId = CAFContext.current.getTenantId();
    BefEngineInfo befEngineInfo = getBefEngineInfoFromCache(beId, version);
    if(befEngineInfo != null)
      return befEngineInfo;

    BETenantInfo beTenantInfo = new BETenantInfo();
    beTenantInfo.setVersion(version);
    beTenantInfo.setTenantId(tenantId);
    if(tenantBEMap.containsKey(beId)){
      tenantBEMap.get(beId).add(beTenantInfo);
    }
    else {
      CopyOnWriteArrayList<BETenantInfo> list = new CopyOnWriteArrayList<>();
      list.add(beTenantInfo);
      tenantBEMap.put(beId, list);
    }
    BefEngineInfo info = new BefEngineInfo();
    info.setCacheVersion(version);
    if(!tenantMap.containsKey(tenantId)){
      tenantMap.put(tenantId, new ConcurrentHashMap<>());
    }
    tenantMap.get(tenantId).put(beId, info);
    return info;
  }

  //从缓存中获取
  private static BefEngineInfo getBefEngineInfoFromCache(String beId, String version){
    int tenantId = CAFContext.current.getTenantId();
    if(!tenantBEMap.containsKey(beId)){
      return null;
    }
    //先查当前租户信息
    CopyOnWriteArrayList<BETenantInfo> copyOnWriteArrayList = tenantBEMap.get(beId);
    if(copyOnWriteArrayList == null)
      return null;
    for(BETenantInfo beTenantInfo : copyOnWriteArrayList){
      //原来使用的ArrayList，多线程下会有null的问题
      if(beTenantInfo == null || beTenantInfo.getTenantId() != tenantId)
        continue;
      if(!beTenantInfo.getVersion().equalsIgnoreCase(version)){
        //版本不一致，缓存失效。。删除
        copyOnWriteArrayList.remove(beTenantInfo);
        if(tenantMap.containsKey(tenantId) && tenantMap.get(tenantId).containsKey(beId)){
          tenantMap.get(tenantId).remove(beId);
        }
        break;
      }
      return tenantMap.get(tenantId).get(beId);
    }

    //查询其他租户对应BE的版本和传入版本是否一致，如果一致，作为当前租户的BefEngineInfo返回，避免重新查询(版本使用时间戳，排除不一致问题)
    for(BETenantInfo beTenantInfo : copyOnWriteArrayList){
      //查询版本与传入版本相同的
      if(beTenantInfo == null || !beTenantInfo.getVersion().equalsIgnoreCase(version)){
        continue;
      }
      BefEngineInfo befEngineInfo = tenantMap.get(beTenantInfo.getTenantId()).get(beId);
      if(befEngineInfo != null && befEngineInfo.getCacheVersion().equalsIgnoreCase(version))
        return befEngineInfo;
      else{
        //容错处理，缓冲中版本不一致，删除（tenantMap中的没有删除）
        if(befEngineInfo != null){
          tenantMap.get(beTenantInfo.getTenantId()).remove(beId);
        }
        copyOnWriteArrayList.remove(beTenantInfo);
        break;
      }
    }
    return null;
  }

  public static void removeBefEngineInfo(String beid) {
    //只删除跟当前租户相关的
    int tenantId = CAFContext.current.getTenantId();
    if(tenantBEMap.containsKey(beid)){
      CopyOnWriteArrayList<BETenantInfo> copyOnWriteArrayList = tenantBEMap.get(beid);
      if(copyOnWriteArrayList != null){
        for(BETenantInfo beTenantInfo : copyOnWriteArrayList){
          if(beTenantInfo.getTenantId() == tenantId){
            copyOnWriteArrayList.remove(beTenantInfo);
            break;
          }
        }
      }
    }
    if(tenantMap.containsKey(tenantId)){
      if(tenantMap.get(tenantId).containsKey(beid)){
        tenantMap.get(tenantId).remove(beid);
      }
    }
  }

  public static void removeAll() {
    int tenantId = CAFContext.current.getTenantId();
    if(tenantMap.containsKey(tenantId)){
      tenantMap.remove(tenantId);
    }
    tenantBEMap.clear();
  }

}
